package com.jjtm.common.core.utils;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author wangbaofeng
 */
public class StringUtil extends StringUtils {
    /**
     * 正则表达式：手机号
     */
    public static final String REGEX_MOBILE = "^((1[3-9][0-9]))\\d{8}$";

    /**
     * 正则表达式：邮件地址
     */
    public static final String REGEX_EMAIL = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";

    /**
     * 正则表达式：URL地址
     */
    public static final String REGEX_URL = "^((ht|f)tps?):\\/\\/[\\w\\-]+(\\.[\\w\\-]+)+([\\w\\-\\.,@?^=%&:\\/~\\+#]*[\\w\\-\\@?^=%&\\/~\\+#])?$";

    /**
     * 正则表达式：身份证号18位
     */
    public static final String REGEX_ID_CARD = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X|x)$";

    /**
     * 正则表达式：身份证号15位
     */
    public static final String REGEX_ID_CARD_OLD = "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$";

    /**
     * 正则表达式：整数
     */
    public static final String REGEX_NUMBER = "\\d*";

    /**
     * 正则表达式：包含中文
     */
    public static final String REGEX_CHINES = "^.*[\\u4e00-\\u9fa5]+.*$";

    /**
     * 正则表达式：全为中文
     */
    public static final String REGEX_CHINES_ALL = "[\\u4e00-\\u9fa5]{2,25}";

    /**
     * 正则表达式：手机浏览器
     */
    public static final String REGEX_UA_PHONE = "\\b(ip(hone|od)|android|opera m(ob|in)i|windows (phone|ce)|blackberry|s(ymbian|eries60|amsung)|p(laybook|alm|rofile/midp|laystation portable)|nokia|fennec|htc[-_]|mobile|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";

    /**
     * 正则表达式：平板浏览器
     */
    public static final String REGEX_UA_TAB = "\\b(ipad|tablet|(Nexus 7)|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";

    /**
     * 正则表达式：用户名（6到16）
     */
    public static String REGEX_USER_NAME = "^([a-zA-Z0-9_]){6,16}$";

    /**
     * 正则表达式：密码（8到20）
     */
    public static String REGEX_PASSWORD = "(?!^(\\d+|[a-zA-Z]+|[~!@#$%^&*?]+)$)^[\\w~!@#$%\\^&*?]{8,20}$";

    /**
     * 正则表达式：银行卡
     */
    public static final String BANK_CARD_NUMBER = "^[1-9]\\d{9,29}$";

    /**
     * 正则表达式：替换
     */
    public static final String REGEX_REPLACE = "\\<.*?\\>";
    public static final String REGEX_REPLACE1 = "\\{.*?\\}";

    private static final Pattern MOBILE = Pattern.compile(REGEX_MOBILE);
    private static final Pattern EMAIL = Pattern.compile(REGEX_EMAIL);
    private static final Pattern URL = Pattern.compile(REGEX_URL);
    private static final Pattern ID_CARD = Pattern.compile(REGEX_ID_CARD);
    private static final Pattern ID_CARD_OLD = Pattern.compile(REGEX_ID_CARD_OLD);
    private static final Pattern NUMBER = Pattern.compile(REGEX_NUMBER);
    private static final Pattern CHINES = Pattern.compile(REGEX_CHINES);
    private static final Pattern CHINES_ALL = Pattern.compile(REGEX_CHINES_ALL);
    private static final Pattern FROM_PHONE = Pattern.compile(REGEX_UA_PHONE);
    private static final Pattern FROM_TAB = Pattern.compile(REGEX_UA_TAB);
    private static Pattern USER_NAME = Pattern.compile(REGEX_USER_NAME);
    private static Pattern PASSWORD = Pattern.compile(REGEX_PASSWORD);
    private static final Pattern REPLACE = Pattern.compile(REGEX_REPLACE);
    private static final Pattern REPLACE1 = Pattern.compile(REGEX_REPLACE1);

    private static final Pattern REPLACE2 = Pattern.compile("\\{(\\d)\\}");

    private static final Pattern BANK_CARD = Pattern.compile(BANK_CARD_NUMBER);

    public static boolean isEmpty(Object str) {
        return str == null || "".equals(str);
    }

    /**
     * 组合传入字符串数组
     *
     * @param objs objs
     * @return String
     */
    public static String getString(Object... objs) {
        if (objs != null && objs.length > 0) {
            StringBuilder sb = new StringBuilder();
            for (Object obj : objs) {
                sb.append(obj == null ? EMPTY : obj.toString());
            }
            return sb.toString();
        }
        return EMPTY;
    }

    /**
     * 首字母变小写
     *
     * @param str str
     * @return String
     */
    public static String firstCharToLowerCase(final String str) {
        char firstChar = str.charAt(0);
        String tail = str.substring(1);
        return Character.toLowerCase(firstChar) + tail;
    }

    /**
     * 首字母变大写
     *
     * @param str str
     * @return String
     */
    public static String firstCharToUpperCase(final String str) {
        char firstChar = str.charAt(0);
        String tail = str.substring(1);
        return Character.toUpperCase(firstChar) + tail;
    }

    /**
     * 转大写
     *
     * @param str str
     * @return String
     */
    public static String toUpperCase(final String str) {

        StringBuilder sb = new StringBuilder();

        for (char strChar : str.toCharArray()) {
            sb.append(Character.toUpperCase(strChar));
        }
        return sb.toString();
    }

    /**
     * 转换为数据库风格（全部小写，下划线分割）
     *
     * @param str str
     * @return String
     */
    public static String toDbStyle(String str) {
        StringBuilder sb = new StringBuilder();
        char c;
        for (int i = 0; i < str.length(); i++) {
            c = str.charAt(i);
            if (Character.isLowerCase(c)) {
                sb.append(c);
            } else {
                if (i > 0) {
                    sb.append("_");
                }
                sb.append(Character.toLowerCase(c));
            }

        }
        return sb.toString();
    }

    /**
     * 转换为Java
     *
     * @param str str
     * @return String
     */
    public static String toJavaStyle(String str) {
        boolean caHang = false;
        StringBuilder sb = new StringBuilder();
        char c;
        for (int i = 0; i < str.length(); i++) {
            c = str.charAt(i);
            if (c == '_') {
                caHang = true;
            } else {
                if (caHang) {
                    c = Character.toUpperCase(c);
                    caHang = false;
                }
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 转换为Java
     *
     * @param str str
     * @return Boolean
     */
    public static String toNum(String str) {
        String regEx = "[^0-9]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.replaceAll("").trim();
    }

    /**
     * 获取字符串的UTF-8字节数组
     *
     * @param message message
     * @return byte[]
     */
    public static byte[] getBytesUtf8(String message) {
        return org.apache.commons.codec.binary.StringUtils.getBytesUtf8(message);
    }

    /**
     * 获取字符串的Base64字节数组
     *
     * @param message message
     * @return byte[]
     */
    public static byte[] getBytesBase64(String message) {
        return Base64.decodeBase64(message);
    }

    /**
     * 根据字节数组构造UTF-8字符串
     *
     * @param message message
     * @return String
     */
    public static String getStringUtf8(byte[] message) {
        String result;
        result = new String(message, StandardCharsets.UTF_8);
        return result;
    }

    /**
     * int类型参数不为null或不为0 主要针对自增型主键,当为0时insert新增 否则为update更新
     */
    public static boolean intIsNotNull(Integer i) {
        return i != null;
    }

    public static boolean longIsNotNull(Long l) {
        return l != null && l != 0;
    }

    /**
     * 根据字节数组构造Base64字符串
     *
     * @param message message
     * @return String
     */
    public static String getStringBase64(byte[] message) {
        return Base64.encodeBase64String(message);
    }

    /**
     * 设定校验用户名及密码的正则表达式，方便扩展
     *
     * @param userName userName
     * @param password password
     */
    public static void setUserNameAndPasswordRegex(String userName, String password) {
        REGEX_USER_NAME = userName;
        USER_NAME = Pattern.compile(REGEX_USER_NAME);

        REGEX_PASSWORD = password;
        PASSWORD = Pattern.compile(REGEX_PASSWORD);
    }

    /**
     * 判断字符串是否为空
     *
     * @param str str
     * @return 空返回false，非空返回true
     */
    public static Boolean isNotBlank(String str) {
        return org.apache.commons.lang3.StringUtils.isNotBlank(str);
    }

    /**
     * 判断字符串是否不为空
     *
     * @param str str
     * @return 空返回true，非空返回false
     */
    public static Boolean isBlank(String str) {
        return org.apache.commons.lang3.StringUtils.isBlank(str);
    }

    /**
     * 截取标识符之前的字符串
     *
     * @param str str
     * @param separator separator
     * @return str
     */
    public static String substringBefore(String str, String separator) {
        return org.apache.commons.lang3.StringUtils.substringBefore(str, separator);
    }

    /**
     * 截取标识符之后的字符串
     *
     * @param str str
     * @param separator separator
     * @return String
     */
    public static String substringAfter(String str, String separator) {
        return org.apache.commons.lang3.StringUtils.substringAfter(str, separator);
    }

    /**
     * 截取最后一个标识符之后的字符串
     *
     * @param str str
     * @param separator separator
     * @return String
     */
    public static String substringAfterLast(String str, String separator) {
        return org.apache.commons.lang3.StringUtils.substringAfterLast(str, separator);
    }

    /**
     * 截取字符串
     *
     * @param str   原始字符串
     * @param start 起始位置
     * @param end   结束位置
     * @return String
     */
    public static String substring(String str, Integer start, Integer end) {
        return org.apache.commons.lang3.StringUtils.substring(str, start, end);
    }

    /**
     * 清楚空字符
     *
     * @param str str
     * @return String
     * @date 2015年4月9日
     */
    public static String trimToEmpty(String str) {
        return org.apache.commons.lang3.StringUtils.trimToEmpty(str);
    }

    /**
     * 判断字符串是否符合用户名格式
     *
     * @param str str
     * @return Boolean
     */
    public static Boolean isUserName(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            matcher = USER_NAME.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 判断字符串是否符合密码格式
     *
     * @param str str
     * @return Boolean
     */
    public static Boolean isPassword(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            matcher = PASSWORD.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 判断字符串是否符合手机号格式
     *
     * @param str str
     * @return Boolean
     */
    public static Boolean isMobile(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            matcher = MOBILE.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 判断字符串是否符合邮件地址格式
     *
     * @param str str
     * @return Boolean
     * @date 2015年4月9日
     */
    public static Boolean isEmail(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            matcher = EMAIL.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 判断字符串是否为URL
     *
     * @param str str
     * @return Boolean
     */
    public static Boolean isUrl(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            matcher = URL.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 判断字符串是否符合身份证格式
     *
     * @param str str
     * @return Boolean
     * @date 2015年4月9日
     */
    public static Boolean isIdCard(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            // 旧身份证长度
            int oldNum = 15;
            // 新身份证长度
            int newNum = 18;
            if (str.length() == newNum) {
                matcher = ID_CARD.matcher(str).matches();
            } else if (str.length() == oldNum) {
                matcher = ID_CARD_OLD.matcher(str).matches();
            }
        }
        return matcher;
    }

    /**
     * 功能描述: 判断是否是银行卡号
     *
     * @return Boolean
     */
    public static Boolean isBankCard(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            matcher = BANK_CARD.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 判断字符串是否为纯数字
     *
     * @param str str
     * @return Boolean
     */
    public static Boolean isNumber(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            matcher = NUMBER.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 判断字符串是否为纯中文
     *
     * @param str str
     * @return Boolean
     */
    public static Boolean isChines(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            matcher = CHINES_ALL.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 判断当前请求是否来自移动端
     *
     * @param ua ua
     * @return Boolean
     */
    public static Boolean fromMobile(String ua) {
        boolean matcher = false;
        if (isNotBlank(ua)) {
            matcher = FROM_PHONE.matcher(ua).matches();
            if (!matcher) {
                matcher = FROM_TAB.matcher(ua).matches();
            }

        }
        return matcher;
    }

    /**
     * 判断字符串是否包含中文
     *
     * @param str str
     * @return Boolean
     */
    public static Boolean containChines(String str) {
        boolean matcher = false;
        if (isNotBlank(str)) {
            matcher = CHINES.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 去除字符串中的Emoji字符
     *
     * @param content content
     * @return String
     * @date 2015年3月29日
     */
    public static String cleanEmoji(String content) {
        if (containsEmoji(content)) {
            StringBuilder sb = new StringBuilder();
            int len = content.length();
            for (int i = 0; i < len; i++) {
                char character = content.charAt(i);
                if (notEmoji(character)) {
                    sb.append(character);
                }
            }
            content = sb.toString();
        }
        return content;
    }

    /**
     * 判断字符串中数否包含Emoji字符串
     *
     * @param content content
     * @return Boolean
     */
    public static Boolean containsEmoji(String content) {
        boolean containsEmoji = false;
        if (StringUtil.isNotBlank(content)) {
            int len = content.length();
            for (int i = 0; i < len; i++) {
                containsEmoji = !notEmoji(content.charAt(i));
                if (containsEmoji) {
                    break;
                }
            }
        }
        return containsEmoji;
    }

    /**
     * 判断字符是否为Emoji
     *
     * @param content content
     * @return Boolean
     */
    private static Boolean notEmoji(char content) {
        return content == 0x0 || content == 0x9 || content == 0xA || content == 0xD || content >= 0x20 && content <= 0xD7FF || content >= 0xE000 && content <= 0xFFFD;
    }

    /**
     * 功能描述:字符串占位符替换
     *
     * @return String
     * @author wangbaofeng
     */
    public static String fillStringByArgs(String str, String[] arr) {
        Matcher m = REPLACE2.matcher(str);
        while (m.find()) {
            str = str.replace(m.group(), arr[Integer.parseInt(m.group(1))]);
        }
        return str;
    }

    /**
     * 字符串转换unicode
     */
    public static String stringToUnicode(String string) {

        StringBuilder unicode = new StringBuilder();

        for (int i = 0; i < string.length(); i++) {

            // 取出每一个字符
            char c = string.charAt(i);

            // 转换为unicode
            unicode.append("\\u").append(Integer.toHexString(c));
        }

        return unicode.toString();
    }

    /**
     * unicode 转字符串
     */
    public static String unicodeToString(String unicode) {

        StringBuilder string = new StringBuilder();

        String[] hex = unicode.split("\\\\u");

        for (int i = 1; i < hex.length; i++) {

            // 转换出每一个代码点
            int data = Integer.parseInt(hex[i], 16);

            // 追加成string
            string.append((char) data);
        }

        return string.toString();
    }

    /**
     * 是否为JSON
     */
    public static boolean isJson(String content) {
        try {
            JSONObject.parseObject(content);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 比较版本号
     */
    public static int compareVersion(String version1, String version2) {
        // 按照.进行分割
        String[] v1 = version1.split("\\.");
        String[] v2 = version2.split("\\.");
        int i = 0;
        // 比对相应的子串
        for (; i < v1.length && i < v2.length; i++) {
            int val1 = Integer.parseInt(v1[i]);
            int val2 = Integer.parseInt(v2[i]);
            if (val1 < val2) {
                return -1;
            }
            if (val1 > val2) {
                return 1;
            }
        }
        // 如果某个版本号更长，判断其多余部分是否是0，如果不是0，则较长的较大，否则是一样的。
        if (v2.length > v1.length) {
            for (; i < v2.length; i++) {
                int val = Integer.parseInt(v2[i]);
                if (val != 0) {
                    return -1;
                }
            }
        } else if (v1.length > v2.length) {
            for (; i < v1.length; i++) {
                int val = Integer.parseInt(v1[i]);
                if (val != 0) {
                    return 1;
                }
            }
        }
        return 0;
    }

    /**
     * 功能描述:判断数组是否包含某个值的方法
     *
     * @return boolean
     */
    public static boolean useList(String[] arr, String targetValue) {
        return Arrays.asList(arr).contains(targetValue);
    }

    public static String replaceHtml(String str) {
        List<String> list = new ArrayList<>();
        Matcher matcher = REPLACE.matcher(str);
        while (matcher.find()) {
            list.add(matcher.group());
        }

        for (String rep : list) {
            str = str.replace(rep, "");
        }
        str = str.replace("&nbsp;", "  ");
        return str;
    }

    public static String replaceParam(String str, Map<String, Object> map) {
        List<String> list = new ArrayList<>();
        Matcher matcher = REPLACE1.matcher(str);
        while (matcher.find()) {
            list.add(matcher.group());
        }

        for (String rep : list) {
            if (map.containsKey(rep)) {
                str = str.replace(rep, map.get(rep).toString());
            } else {
                str = str.replace(rep, " ***");
            }
        }

        return str;
    }

}
